package com.mdd.admin.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.binarywang.wxpay.bean.notify.*;
import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryV3Result;
import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryV3Result;
import com.github.binarywang.wxpay.bean.result.WxPayRefundV3Result;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.mdd.admin.service.order.IOrderRefundService;
import com.mdd.common.entity.order.Order;
import com.mdd.common.entity.order.OrderCourse;
import com.mdd.common.enums.OrderEnum;
import com.mdd.common.enums.OrderRefundEnum;
import com.mdd.common.utils.TimeUtil;
import org.apache.commons.io.IOUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * @author panweiliang
 */
@RestController
@RequestMapping("/api/pay/wx")
public class WxPayController {
  @Resource
  private WxPayService wxService;

  @Resource
  private IOrderRefundService orderRefundService;

  /**
   * <pre>
   * 查询订单(详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2)
   * 该接口提供所有微信支付订单的查询，商户可以通过查询订单接口主动查询订单状态，完成下一步的业务逻辑。
   * 需要调用查询接口的情况：
   * ◆ 当商户后台、网络、服务器等出现异常，商户系统最终未接收到支付通知；
   * ◆ 调用支付接口后，返回系统错误或未知交易状态情况；
   * ◆ 调用被扫支付API，返回USERPAYING的状态；
   * ◆ 调用关单或撤销接口API之前，需确认支付状态；
   * 接口地址：https://api.mch.weixin.qq.com/pay/orderquery
   * </pre>
   *
   * @param transactionId 微信订单号
   * @param outTradeNo    商户系统内部的订单号，当没提供transactionId时需要传这个。
   */
  @GetMapping("/queryOrder")
  public WxPayOrderQueryV3Result queryOrder(@RequestParam(required = false) String transactionId,
                                          @RequestParam(required = false) String outTradeNo)
    throws WxPayException {

    return this.wxService.queryOrderV3(transactionId, outTradeNo);
  }

  @PostMapping("/queryOrder")
  public WxPayOrderQueryV3Result queryOrder(@RequestBody WxPayOrderQueryV3Request wxPayOrderQueryV3Request) throws WxPayException {
    return this.wxService.queryOrderV3(wxPayOrderQueryV3Request);
  }

  /**
   * <pre>
   * 关闭订单
   * 应用场景
   * 以下情况需要调用关单接口：
   * 1. 商户订单支付失败需要生成新单号重新发起支付，要对原订单号调用关单，避免重复支付；
   * 2. 系统下单后，用户支付超时，系统退出不再受理，避免用户继续，请调用关单接口。
   * 注意：订单生成后不能马上调用关单接口，最短调用时间间隔为5分钟。
   * 接口地址：https://api.mch.weixin.qq.com/pay/closeorder
   * 是否需要证书：   不需要。
   * </pre>
   *
   * @param outTradeNo 商户系统内部的订单号
   */
  @GetMapping("/closeOrder/{outTradeNo}")
  public void closeOrder(@PathVariable String outTradeNo) throws WxPayException {
    this.wxService.closeOrderV3(outTradeNo);
  }

  //关闭订单
  @PostMapping("/closeOrder")
  public void closeOrder(@RequestBody WxPayOrderCloseRequest wxPayOrderCloseRequest) throws WxPayException {
    this.wxService.closeOrder(wxPayOrderCloseRequest);
  }

  /**
   * 调用统一下单接口，并组装生成支付所需参数对象.
   *
   * @param request 统一下单请求参数
   * @param <T>     请使用{@link com.github.binarywang.wxpay.bean.order}包下的类
   * @return 返回 {@link com.github.binarywang.wxpay.bean.order}包下的类对象
   */
  @PostMapping("/createOrder")
  public <T> T createOrder(@RequestBody WxPayUnifiedOrderV3Request request) throws WxPayException {
    return this.wxService.createOrderV3(TradeTypeEnum.JSAPI, request);
  }

  /**
   * <pre>
   * 微信支付-申请退款
   * 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
   * 接口链接：https://api.mch.weixin.qq.com/secapi/pay/refund
   * </pre>
   *
   * @param request 请求对象
   * @return 退款操作结果
   */
  @PostMapping("/refund")
  public WxPayRefundV3Result refund(@RequestBody WxPayRefundV3Request request) throws WxPayException {
    return this.wxService.refundV3(request);
  }

  /**
   * <pre>
   * 微信支付-查询退款
   * 应用场景：
   *  提交退款申请后，通过调用该接口查询退款状态。退款有一定延时，用零钱支付的退款20分钟内到账，
   *  银行卡支付的退款3个工作日后重新查询退款状态。
   * 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_5
   * 接口链接：https://api.mch.weixin.qq.com/pay/refundquery
   * </pre>
   * 以下四个参数四选一
   *
   * @param outRefundNo   商户退款单号
   * @return 退款信息
   */
  @GetMapping("/refundQuery")
  public WxPayRefundQueryV3Result refundQuery(@RequestParam(required = false) String outRefundNo)
    throws WxPayException {
    return this.wxService.refundQueryV3(outRefundNo);
  }

  @PostMapping("/refundQuery")
  public WxPayRefundQueryV3Result refundQuery(@RequestBody WxPayRefundQueryV3Request wxPayRefundQueryV3Request) throws WxPayException {
    return this.wxService.refundQueryV3(wxPayRefundQueryV3Request);
  }

//  支付回调通知处理
  @PostMapping("/notify/refund")
  public String parseRefundNotifyResult(@RequestBody String jsonData, HttpServletRequest request) throws WxPayException {
    // TODO 根据自己业务场景需要构造返回对象
    SignatureHeader signatureHeader = this.getRequestHeader(request);
    this.orderRefundService.parseRefundNotify(jsonData, signatureHeader);
    return WxPayNotifyResponse.success("成功");
  }

  /**
   * 获取回调请求头：签名相关
   *
   * @param request HttpServletRequest
   * @return SignatureHeader
   */
  public SignatureHeader getRequestHeader(HttpServletRequest request) {
    // 获取通知签名
    String signature = request.getHeader("wechatpay-signature");
    String nonce = request.getHeader("wechatpay-nonce");
    String serial = request.getHeader("wechatpay-serial");
    String timestamp = request.getHeader("wechatpay-timestamp");

    SignatureHeader signatureHeader = new SignatureHeader();
    signatureHeader.setSignature(signature);
    signatureHeader.setNonce(nonce);
    signatureHeader.setSerial(serial);
    signatureHeader.setTimeStamp(timestamp);
    return signatureHeader;
  }

//  扫码支付回调通知处理
  @PostMapping("/notify/scanpay")
  public String parseScanPayNotifyResult(String xmlData) throws WxPayException {
    final WxScanPayNotifyResult result = this.wxService.parseScanPayNotifyResult(xmlData);
    // TODO 根据自己业务场景需要构造返回对象
    return WxPayNotifyResponse.success("成功");
  }

}

